#region File Description
//-----------------------------------------------------------------------------
// Author: JCBDigger
// URL: http://Games.DiscoverThat.co.uk
// Modified from the samples provided by
// Microsoft XNA Community Game Platform
//-----------------------------------------------------------------------------
#endregion

using System;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Specialized;
using AssetData;
using AssetContent;

namespace Engine
{
    /// <summary>
    /// Custom form provides the main user interface for the program.
    /// In this sample we used the designer to fill the entire form with a
    /// ModelViewerControl, except for the menu bar which provides the
    /// "File / Open..." option.
    /// </summary>
    public partial class MainForm : Form
    {
        private ContentBuilder contentBuilder;
        private ContentManager contentManager;

        private string defaultFileFolder = "";
        public string DefaultFileFolder
        {
            get { return defaultFileFolder; }
        }

        private string lastLoadedFile = "";

        /// <summary>
        /// Constructs the main form.
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            contentBuilder = new ContentBuilder();

            contentManager = new ContentManager(modelViewerControl.Services,
                                                contentBuilder.OutputDirectory);
            // A folder in the users MyDocuments
            defaultFileFolder = GetSavePath();

            UpdateMenuItemVisibility();

            modelViewerControl.IsMoving += new EventHandler<EventArgs>(modelViewerControl_IsMoving);
            modelViewerControl.Click += new EventHandler(modelViewerControl_Click);
            modelViewerControl.ChangedOrbit += new EventHandler<EventArgs>(modelViewerControl_ChangedOrbit);
        }

        
        /////////////////////////////////////////////////////////////////////
        // == Changes ==
        //
        public void Orbit(bool change, float turnSpeed)
        {
            orbitTheModelMenu.Checked = change;
            statusOrbit.Visible = change;
            modelViewerControl.OrbitMode = change;
            modelViewerControl.AutoRotateSpeed = turnSpeed;
        }

        private void orbitTheModelMenu_Click(object sender, EventArgs e)
        {
            Orbit(!orbitTheModelMenu.Checked, 0);
        }

        private void modelViewerControl_ChangedOrbit(object sender, EventArgs e)
        {
            UpdateOrbitStatus();
        }

        private void ClipNamesComboBox_GotFocus(object sender, EventArgs e)
        {
            // The orbit mode causes problems with the drop down so has to be disabled
            Orbit(false, 0);
        }

        //
        /////////////////////////////////////////////////////////////////////

        /// <summary>
        /// See also DefaultFileFolder
        /// </summary>
        public static string GetSavePath()
        {
            string result = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                GlobalSettings.pathSaveGameFolder, GlobalSettings.pathSaveDataFolder);
            if (!Directory.Exists(result))
            {
                Directory.CreateDirectory(result);
            }
            return result;
        }

        //////////////////////////////////////////////////////////////////////
        // == Setup ==
        //
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            ShowFloor(true);
            ShowAxes(true);
            modelViewerControl.PauseInput = false;
            menuStrip1.MenuActivate += new EventHandler(menuStrip1_MenuActivate);
            menuStrip1.MenuDeactivate += new EventHandler(menuStrip1_MenuDeactivate);
        }

        private void menuStrip1_MenuDeactivate(object sender, EventArgs e)
        {
            PauseGameInput(false);
        }

        private void menuStrip1_MenuActivate(object sender, EventArgs e)
        {
            PauseGameInput(true);
        }

        private void PauseGameInput(bool change)
        {
            modelViewerControl.PauseInput = change;
        }

        private void modelViewerControl_Click(object sender, EventArgs e)
        {
            ParkCursor();
        }

        private void modelViewerControl_IsMoving(object sender, EventArgs e)
        {
            ParkCursor();
        }

        /// <summary>
        /// Move the cursor to an unused dialogue while the model is being moved
        /// this is to avoid unexpected menu changes
        /// </summary>
        public void ParkCursor()
        {
            modelViewerControl.Focus();
        }

        private void resetViewingPoint_Click(object sender, EventArgs e)
        {
            modelViewerControl.InitialiseCameraPosition();
        }

        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        // == File ==
        //
        private void OpenRigidModelMenu_Click(object sender, EventArgs e)
        {
            // Find out what file we want to open
            OpenFileDialog fileDialog = new OpenFileDialog();

            fileDialog.InitialDirectory = defaultFileFolder;

            fileDialog.Title = "Load Rigid Model";

            fileDialog.Filter = "Model Files (*.fbx;*.x)|*.fbx;*.x|" +
                                "FBX Files (*.fbx)|*.fbx|" +
                                "X Files (*.x)|*.x|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                lastLoadedFile = fileDialog.FileName;
                //LoadModel(fileDialog.FileName);
            }
            UpdateMenuItemVisibility();
        }

        /// <summary>
        /// Event handler for the Exit menu option.
        /// </summary>
        private void ExitMenu_Click(object sender, EventArgs e)
        {
            Close();
        }
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        // == View and Help ==
        //
        // Remember what was set between changing views
        private bool previousShowFloor = true;

        private void showFloor_Click(object sender, EventArgs e)
        {
            ShowFloor(!showFloorMenuItem.Checked);
            // Remember the current setting so we can change back after changing views
            previousShowFloor = showFloorMenuItem.Checked;
        }

        public void ShowFloor(bool show)
        {
            if (show && modelViewerControl.Floor == null)
            {
                Loader contentLoad = new Loader(modelViewerControl.Services);
                modelViewerControl.SetFloor(contentLoad.GetModel("grid100x100"));
            }
            showFloorMenuItem.Checked = show;
            showFloorMenuItem.Checked = modelViewerControl.ShowFloor(show);
        }


        private void showAxesMenuItem_Click(object sender, EventArgs e)
        {
            ShowAxes(!showAxesMenuItem.Checked);
        }

        private void ShowAxes(bool show)
        {
            if (show && !modelViewerControl.IsAxisFontLoaded())
            {
                Loader contentLoad = new Loader(modelViewerControl.Services);
                modelViewerControl.SetAxisFont(contentLoad.GetFont("Axis"));
            }
            showAxesMenuItem.Checked = show;
            modelViewerControl.ShowAxes = show;
        }


        private void wireframeItem_Click(object sender, EventArgs e)
        {
            wireframeItem.Checked = !wireframeItem.Checked;
            modelViewerControl.WireFrameEnable(wireframeItem.Checked);
        }

        private void invertYControlsItem_Click(object sender, EventArgs e)
        {
            invertYControlsItem.Checked = !invertYControlsItem.Checked;
            modelViewerControl.InvertY = invertYControlsItem.Checked;
        }

        private void helpToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            HelpForm aForm = new HelpForm();
            aForm.ShowDialog();
            PauseGameInput(false);
        }

        private void featuresToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            FeaturesForm aForm = new FeaturesForm();
            aForm.ShowDialog();
            PauseGameInput(false);
        }
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        // == Menu Visibility ==
        //
        public void UpdateMenuItemVisibility()
        {
            WhatLighting();
            UpdateOrbitStatus();
        }

        private void UpdateOrbitStatus()
        {
            statusOrbit.Visible = false;
            if (modelViewerControl != null)
            {
                orbitTheModelMenu.Checked = modelViewerControl.OrbitMode;
                statusOrbit.Visible = orbitTheModelMenu.Checked;
            }
        }

        private void WhatLighting()
        {
            light1EnabledToolStripMenuItem.Checked = modelViewerControl.Light1Enabled;
            light2EnabledToolStripMenuItem.Checked = modelViewerControl.Light2Enabled;
            reverseLightingToolStripMenuItem.Checked = modelViewerControl.ReverseLighting;
        }
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        // == Load and Save ==
        //
        // Returns the name of the saved file
        private string SampleSaveDialogue(List<string> data, string file)
        {
            // Path to default location
            string pathToSaveFolder = defaultFileFolder;
            string assetName = "";
            string fileName = file;
            // If we have loaded a file use that for the path and the name
            if (lastLoadedFile != "")
            {
                pathToSaveFolder = Path.GetDirectoryName(lastLoadedFile);
                assetName = Path.GetFileNameWithoutExtension(lastLoadedFile) + "-";
            }
            // Append the name to the end of the filename
            fileName = assetName + fileName;

            SaveFileDialog fileDialog = new SaveFileDialog();

            fileDialog.InitialDirectory = pathToSaveFolder;

            fileDialog.Title = "Save the animation clip";

            fileDialog.FileName = fileName;

            fileDialog.Filter = "Clip File (*.clip)|*.clip|" +
                                "Head File (*.head)|*.head|" +
                                "Arms File (*.arms)|*.arms|" +
                                "Animation File Types (*.clip;*.arms;*.head)|*.clip;*.arms;*.head|" +
                                "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                SaveTextFile(fileDialog.FileName, data);
                return fileDialog.FileName;
            }
            return "";
        }

        /// <summary>
        /// Used from various classes to save files
        /// </summary>
        public void SaveTextFile(string fileName, List<string> data)
        {
            if (data.Count < 1 || string.IsNullOrEmpty(fileName))
            {
                return;
            }

            Cursor = Cursors.WaitCursor;

            File.WriteAllLines(fileName, data);

            Cursor = Cursors.Arrow;

        }

        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        // == Diabolical Menu Actions ==
        //
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PauseGameInput(true);
            OptionsForm aForm = new OptionsForm();
            aForm.MovementSpeed = modelViewerControl.CurrentMoveSpeed;
            aForm.TurnSpeed = modelViewerControl.CurrentTurnSpeed;
            aForm.GridSquareWidth = modelViewerControl.GridSquareWidth.ToString();
            DialogResult diagResult = aForm.ShowDialog();
            if (diagResult == DialogResult.OK)
            {
                modelViewerControl.CurrentMoveSpeed = aForm.MovementSpeed;
                modelViewerControl.CurrentTurnSpeed = aForm.TurnSpeed;
            }
            PauseGameInput(false);
        }

        //
        //////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        // == File Utilities ==
        //
        /// <summary>
        /// Creates a relative path from one file
        /// or folder to another.
        /// http://weblogs.asp.net/pwelter34/archive/2006/02/08/create-a-relative-path-code-snippet.aspx
        /// </summary>
        /// <param name="fromDirectory">
        /// Contains the directory that defines the 
        /// start of the relative path.
        /// </param>
        /// <param name="toPath">
        /// Contains the path that defines the
        /// endpoint of the relative path.
        /// </param>
        /// <returns>
        /// The relative path from the start
        /// directory to the end path.
        /// </returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static string RelativePathTo(
            string fromDirectory, string toPath)
        {
            if (fromDirectory == null)
            {
                throw new ArgumentNullException("fromDirectory");
            }

            if (toPath == null)
            {
                throw new ArgumentNullException("toPath");
            }

            bool isRooted = Path.IsPathRooted(fromDirectory) && Path.IsPathRooted(toPath);

            if (isRooted)
            {
                bool isDifferentRoot = string.Compare(
                    Path.GetPathRoot(fromDirectory),
                    Path.GetPathRoot(toPath), true) != 0;

                if (isDifferentRoot)
                {
                    return toPath;
                }
            }

            StringCollection relativePath = new StringCollection();

            string[] fromDirectories = fromDirectory.Split(
                Path.DirectorySeparatorChar);

            string[] toDirectories = toPath.Split(
                Path.DirectorySeparatorChar);

            int length = Math.Min(
                fromDirectories.Length,
                toDirectories.Length);

            int lastCommonRoot = -1;

            // find common root
            for (int x = 0; x < length; x++)
            {
                if (string.Compare(fromDirectories[x],
                    toDirectories[x], true) != 0)
                {
                    break;
                }

                lastCommonRoot = x;
            }

            if (lastCommonRoot == -1)
            {
                return toPath;
            }

            // add relative folders in from path
            for (int x = lastCommonRoot + 1; x < fromDirectories.Length; x++)
            {
                if (fromDirectories[x].Length > 0)
                {
                    relativePath.Add("..");
                }
            }

            // add to folders to path
            for (int x = lastCommonRoot + 1; x < toDirectories.Length; x++)
            {
                relativePath.Add(toDirectories[x]);
            }

            // create relative path
            string[] relativeParts = new string[relativePath.Count];
            relativePath.CopyTo(relativeParts, 0);

            string newPath = string.Join(
                Path.DirectorySeparatorChar.ToString(),
                relativeParts);

            return newPath;
        }
        //
        //////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        // == Colours and Lighting==
        //
        public void SetMaterialColours(float specularPower, Vector3 specularColour, Vector3 diffuseColour, Vector3 emissiveColour)
        {
            modelViewerControl.SpecularPower = specularPower;
            modelViewerControl.SpecularColour = specularColour;
            modelViewerControl.DiffuseColour = diffuseColour;
            modelViewerControl.EmissiveColour = emissiveColour;
        }

        private void light1EnabledToolStripMenuItem_Click(object sender, EventArgs e)
        {
            modelViewerControl.Light1Enabled = !modelViewerControl.Light1Enabled;
            light1EnabledToolStripMenuItem.Checked = modelViewerControl.Light1Enabled;
        }

        private void light2EnabledToolStripMenuItem_Click(object sender, EventArgs e)
        {
            modelViewerControl.Light2Enabled = !modelViewerControl.Light2Enabled;
            light2EnabledToolStripMenuItem.Checked = modelViewerControl.Light2Enabled;
        }

        private void reverseLightingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            modelViewerControl.ReverseLighting = !modelViewerControl.ReverseLighting;
            reverseLightingToolStripMenuItem.Checked = modelViewerControl.ReverseLighting;
        }
        //
        //////////////////////////////////////////////////////////////////////
    }
}
